/*  ----------------------------------------------------------------------------
 *  Arello Mobile
 *  Fast 3d Engine
 *  ----------------------------------------------------------------------------
 * Except where otherwise noted, this work is licensed under
 * http://creativecommons.org/licenses/by/3.0
 */

#ifndef __XMLOBJECTSMART_H__
#define __XMLOBJECTSMART_H__

#include "Object.h"
#include <Converter.h>
#include "Saver.h"
#include "Stream.h"
///#include <Thread/Lock.h>

namespace liba
{
namespace xml
{

class ObjectSmart;

typedef ObjectUnicode ObjectPreferred;
typedef std::wstring StringPreferred;

class ObjectSmartable
{
public:
	ObjectSmartable * next;
	ObjectSmartable( ObjectSmart * object );

	virtual bool on_base_data( Provider * prov, const void * data, unsigned size )
	{
		return false;
	}
	virtual void on_base_save_attributes( SaverBase * saver )const
	{}
	virtual void on_base_save_nodes( SaverBase * saver )const
	{}
	virtual void on_base_save_data( SaverBase * saver )const
	{}
	virtual bool on_base_node( Provider * prov, const StringPreferred & name )
	{
		return false;
	}
	virtual bool on_base_attribute( Provider * prov, const StringPreferred & name, const StringPreferred & value )
	{
		return false;
	}
};

template<class T>
class Attribute : public ObjectSmartable
{
public:
	Attribute( ObjectSmart * object, const std::string & name, const T & default_value = T() )
		:	ObjectSmartable( object ),
		val( default_value )
	{
		converter::convert( name, &(this->name) );
	}
	Attribute( ObjectSmart * object, const std::wstring & name, const T & default_value = T() )
		:	ObjectSmartable( object ),
		val( default_value )
	{
		converter::convert( name, &(this->name) );
	}
	Attribute( ObjectSmart * object, const Attribute<T> & attr )
	:	ObjectSmartable( object ),
		name( attr.name ),
		val( attr.val )
	{}
	const Attribute<T> & operator=( const Attribute<T> & attr )
	{
		if( this != &attr )
		{
			name = attr.name;
			val = attr.val;
		}
		return *this;
	}
	operator T & ()
	{
		return val;
	}
	operator const T & ()const
	{
		return val;
	}
	T & data()
	{
		return val;
	}
	const T & data()const
	{
		return val;
	}
private:
	Attribute( const Attribute<T> & attr );
	T val;
	virtual bool on_base_attribute( Provider * prov, const StringPreferred & name, const StringPreferred & value )
	{
		if( name == this->name )
			return converter::convert( value, &val );
		return false;
	}
	virtual void on_base_save_attributes( SaverBase * saver )const
	{
		saver->save_attribute( name, val );
	}
	StringPreferred name;
};

class Data : public ObjectSmartable
{
public:
	Data( ObjectSmart * object )
	:	ObjectSmartable( object )
	{}
	Data( ObjectSmart * object, const Data & attr )
	:	ObjectSmartable( object ),
		val( attr.val )
	{}
	const Data & operator=( const Data & attr )
	{
		if( this != &attr )
		{
			val = attr.val;
		}
		return *this;
	}
	const std::string & data()const
	{
		return val;
	}
	std::string & data()
	{
		return val;
	}
private:
	Data( const Data & attr );
	std::string val;
	virtual bool on_base_data( Provider * prov, const void * data, unsigned size )
	{
		const char * begin = static_cast<const char *>( data );
		val.assign( begin, begin + size );
		return true;
	}
	virtual void on_base_save_data( SaverBase * saver )const
	{
		saver->save_data( val.data(), val.size() );
	}
};


template<class T>
class Node : public T, public ObjectSmartable
{
public:
	typedef T value_type;

	Node( ObjectSmart * object, const char * name, const T & default_value )
		:	ObjectSmartable( object ),
		value_type( default_value )
	{
		std::string tmp( name );
		converter::convert( tmp, &(this->name) );
	}
	Node( ObjectSmart * object, const char * name )
		:	ObjectSmartable( object )
	{
		std::string tmp( name );
		converter::convert( tmp, &(this->name) );
	}

	Node( ObjectSmart * object, const std::string & name, const T & default_value )
		:	ObjectSmartable( object ),
		value_type( default_value )
	{
		converter::convert( name, &(this->name) );
	}
	Node( ObjectSmart * object, const std::string & name )
		:	ObjectSmartable( object )
	{
		converter::convert( name, &(this->name) );
	}
	Node( ObjectSmart * object, const std::wstring & name, const T & default_value )
		:	ObjectSmartable( object ),
		value_type( default_value )
	{
		converter::convert( name, &(this->name) );
	}
	Node( ObjectSmart * object, const std::wstring & name )
		:	ObjectSmartable( object )
	{
		converter::convert( name, &(this->name) );
	}
	Node( ObjectSmart * object, const Node<T> & attr )
	:	ObjectSmartable( object ),
		name( attr.name ),
		value_type( attr )
	{}
	const Node<T> & operator=( const Node<T> & attr )
	{
		if( this != &attr )
		{
			name = attr.name;
			this->value_type::operator=( attr );
		}
		return *this;
	}

private:
	Node( const Node<T> & attr );
	virtual bool on_base_node( Provider * prov, const StringPreferred & name )
	{
		if( name == this->name )
			return prov->parse_object( this );
		return false;
	}
	virtual void on_base_save_nodes( SaverBase * saver )const
	{
		saver->save_node( name, this );
	}
	StringPreferred name;
};

template<class T>
class MultiNode : public T, public ObjectSmartable
{
public:
	typedef T value_type;
	MultiNode( ObjectSmart * object, const std::string & name )
		:	ObjectSmartable( object )
	{
		converter::convert( name, &(this->name) );
	}
	MultiNode( ObjectSmart * object, const std::wstring & name )
		:	ObjectSmartable( object )
	{
		converter::convert( name, &(this->name) );
	}
	MultiNode( ObjectSmart * object, const MultiNode<T> & attr )
	:	ObjectSmartable( object ),
		name( attr.name ),
		value_type( attr )
	{}
	const MultiNode<T> & operator=( const MultiNode<T> & attr )
	{
		if( this != &attr )
		{
			name = attr.name;
			this->value_type::operator=( attr );
		}
		return *this;
	}
private:
	MultiNode( const MultiNode<T> & attr );
	virtual bool on_base_node( Provider * prov, const StringPreferred & name )
	{
		if( name == this->name )
		{
			push_back( T::value_type() );
			return prov->parse_object( &T::back() );
		}
		return false;
	}
	virtual void on_base_save_nodes( SaverBase * saver )const
	{
		typename T::const_iterator cit = T::begin();
		for( ; cit != T::end(); ++cit )
			saver->save_node( name, &*cit );
	}
	StringPreferred name;
};


class ObjectSmart : public ObjectPreferred
{
	ObjectSmartable * base;
public:
	ObjectSmart():
		base( 0 )
	{}
	virtual ~ObjectSmart()
	{}
	ObjectSmart(const ObjectSmart & obj):
		base( 0 )
	{}
	const ObjectSmart & operator=(const ObjectSmart & obj)
	{
		return *this;
	}
	void register_this( ObjectSmartable * next )
	{
		next->next = base;
		base = next;
	}
	virtual bool on_node( Provider * prov, const StringPreferred & name )
	{
		ObjectSmartable * curr = base;
		for( ; curr ; curr = curr->next )
			if( curr->on_base_node( prov, name ) )
				return true;
		return false;
	}
	virtual bool on_attribute( Provider * prov, const StringPreferred & name, const StringPreferred & value )
	{
		ObjectSmartable * curr = base;
		for( ; curr ; curr = curr->next )
			if( curr->on_base_attribute( prov, name, value ) )
				return true;
		return false;
	}
	virtual bool on_data( Provider * prov, const void * data, unsigned size )
	{
		ObjectSmartable * curr = base;
		for( ; curr ; curr = curr->next )
			if( curr->on_base_data( prov, data, size ) )
				return true;
		return false;
	}
	virtual void on_save_attributes( SaverBase * saver )const
	{
		ObjectSmartable * curr = base;
		for( ; curr ; curr = curr->next )
			curr->on_base_save_attributes( saver );
	}
	virtual void on_save_nodes( SaverBase * saver )const
	{
		ObjectSmartable * curr = base;
		for( ; curr ; curr = curr->next )
			curr->on_base_save_nodes( saver );
	}
	virtual void on_save_data( SaverBase * saver )const
	{
		ObjectSmartable * curr = base;
		for( ; curr ; curr = curr->next )
			curr->on_base_save_data( saver );
	}
};

inline ObjectSmartable::ObjectSmartable( ObjectSmart * object)
	:	next( 0 )
{
	object->register_this( this );
}

} // namespace xml
} // namespace liba

using namespace liba;

#endif //__XMLOBJECTSMART_H__

